package com.example.springbootoauth2jwtclientserver.security;

import com.alibaba.fastjson.JSONObject;
import com.example.springbootoauth2jwtclientserver.exception.CustomException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpRequest;
import org.springframework.http.HttpStatus;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails;
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetailsSource;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

@Slf4j
public class OAuth2ResourceRestTemplateUtil {
    private static RestTemplate restTemplate;
    private static SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
    private static List<ClientHttpRequestInterceptor> list = new ArrayList<>();
    static{
        factory.setConnectTimeout(5000);
        factory.setReadTimeout(5000);
        list.add(new RetryInterceptor());
        list.add(new HeaderLoggingInterceptor());
    }

    public OAuth2ResourceRestTemplateUtil() {
    }

    public static RestTemplate getRestTemplate(){
        if (restTemplate == null) {
            synchronized (OAuth2ResourceRestTemplateUtil.class){
                if (restTemplate == null) {
                    restTemplate = new RestTemplate();
                    restTemplate.setInterceptors(list);
                }
            }
        }
        return restTemplate;
    }

    private static class RetryInterceptor implements ClientHttpRequestInterceptor{

        private int maxRetry = 3;
        private int retryNum = 0;

        public RetryInterceptor() {
        }

        public RetryInterceptor(int maxRetry) {
            this.maxRetry = maxRetry;
        }

        @Override
        public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
            ClientHttpResponse response = execution.execute(request, body);
            if (!response.getStatusCode().equals(HttpStatus.OK) && retryNum < maxRetry) {
                retryNum++;
                response = execution.execute(request, body);
            }
            return response;
        }

    }

    private static class HeaderLoggingInterceptor implements ClientHttpRequestInterceptor{

        @Override
        public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {

            try {
                OAuth2Authentication oAuth2Authentication = (OAuth2Authentication) SecurityContextHolder.getContext().getAuthentication();
                OAuth2AuthenticationDetails oAuth2AuthenticationDetails = (OAuth2AuthenticationDetails) oAuth2Authentication.getDetails();
                String tokenType = oAuth2AuthenticationDetails.getTokenType();
                String tokenValue = oAuth2AuthenticationDetails.getTokenValue();
                request.getHeaders().add("authorization",tokenType + " " + tokenValue);
            } catch (Exception e) {
                throw new CustomException(HttpStatus.FORBIDDEN,e.getMessage(),e.getClass().getName());
            }
            log.info("请求地址：{}", request.getURI());
            log.info("请求头信息：{}", JSONObject.toJSONString(request.getHeaders(),true));
            ClientHttpResponse response = execution.execute(request, body);
            log.info("响应头信息：{}",JSONObject.toJSONString(response.getHeaders(),true));
            return response;
        }
    }
}
